import uuid
import socket
import getpass
import subprocess
import ctypes
import sys
import time
import psutil
from ctypes import wintypes


"""
===================
反沙箱
===================
"""

def is_virtual_machine():
    mac = ':'.join(['{:02x}'.format((uuid.getnode() >> ele) & 0xff)
                    for ele in range(0, 2*6, 8)][::-1])
    suspicious_macs = ['00:05:69', '00:0C:29', '00:1C:14', '00:50:56']  # VMware/VirtualBox MAC
    for vm_mac in suspicious_macs:
        if mac.startswith(vm_mac.lower()):
            return True

    try:
        manufacturer = subprocess.check_output('wmic computersystem get manufacturer', shell=True).decode().lower()
        if 'vmware' in manufacturer or 'virtual' in manufacturer:
            return True
    except:
        pass
    return False

def is_low_memory():
    mem = psutil.virtual_memory()
    return mem.total < 2 * 1024 ** 3  # 小于2GB认为是沙箱

def is_sandbox_user():
    username = getpass.getuser().lower()
    hostname = socket.gethostname().lower()
    keywords = ['sandbox', 'virus', 'malware', 'test', 'lab', 'win7']
    return any(k in username or k in hostname for k in keywords)

def has_suspicious_processes():
    suspicious = ['vboxservice', 'wireshark', 'procmon', 'fiddler']
    for proc in psutil.process_iter(['name']):
        try:
            if proc.info['name'] and any(s in proc.info['name'].lower() for s in suspicious):
                return True
        except (psutil.NoSuchProcess, psutil.AccessDenied):
            continue
    return False

def xor_encrypt(data: bytes, key: str) -> bytes:
    key_bytes = key.encode()
    key_len = len(key_bytes)
    return bytes([b ^ key_bytes[i % key_len] for i, b in enumerate(data)])

def xor_decrypt(encrypted_data: bytes, key: str) -> bytes:
    return xor_encrypt(encrypted_data, key)


"""
===================
反调试
===================
"""



# 检查 IsDebuggerPresent 和 CheckRemoteDebuggerPresent
def is_debugger_present_combined():
    kernel32 = ctypes.windll.kernel32
    h_process = kernel32.GetCurrentProcess()
    remote_present = wintypes.BOOL()
    kernel32.CheckRemoteDebuggerPresent(h_process, ctypes.byref(remote_present))
    return kernel32.IsDebuggerPresent() != 0 or remote_present.value != 0

# 读取 PEB 的 BeingDebugged 字节（通过 NtQueryInformationProcess）
def is_being_debugged_peb():
    PROCESS_BASIC_INFORMATION = ctypes.c_ulong * 6
    pbi = PROCESS_BASIC_INFORMATION()
    h_process = ctypes.windll.kernel32.GetCurrentProcess()
    ntdll = ctypes.windll.ntdll
    NtQueryInformationProcess = ntdll.NtQueryInformationProcess
    ret_len = ctypes.c_ulong()
    status = NtQueryInformationProcess(
        h_process, 0, ctypes.byref(pbi), ctypes.sizeof(pbi), ctypes.byref(ret_len)
    )
    if status != 0:
        return False
    peb_base = pbi[1]
    being_debugged = ctypes.c_ubyte()
    bytes_read = ctypes.c_ulong()
    ctypes.windll.kernel32.ReadProcessMemory(
        h_process,
        peb_base + 2,  # offset for BeingDebugged
        ctypes.byref(being_debugged),
        1,
        ctypes.byref(bytes_read)
    )
    return being_debugged.value != 0

# 调用 DebugBreak，若被调试器接管则不会崩溃
def detect_debug_break():
    try:
        ctypes.windll.kernel32.DebugBreak()
        return True  # 没有崩溃说明有调试器接管
    except:
        return False  # 没有调试器会崩溃（通常抓不到异常）

# 检查父进程是否为常见调试器
# def is_launched_by_debugger():
#     try:
#         current = psutil.Process()
#         while current:
#             parent = current.parent()
#             if not parent:
#                 break
#             name = parent.name().lower()
#             if any(dbg in name for dbg in ['x64dbg', 'ida', 'ollydbg', 'windbg', 'dbg']):
#                 return True
#             current = parent
#         return False

def get_parent_chain_names():
    names = []
    try:
        proc = psutil.Process()
        while proc:
            proc = proc.parent()
            if not proc:
                break
            name = proc.name().lower()
            names.append(name)
    except Exception as e:
        print(f"[-] 获取父进程链失败: {e}")
    return names

def is_launched_by_debugger():
    suspicious_keywords = ["ollydbg", "x64dbg", "ida", "windbg", "processhacker", "debug"]  # 可精简
    chain = get_parent_chain_names()
    print("[*] 父进程链:", " -> ".join(chain))  # 打印调试用
    return any(any(keyword in name for keyword in suspicious_keywords) for name in chain)


# 检查 sleep 是否被 Hook（时间差明显大于真实延迟）
def check_time_drift_strict():
    start = time.perf_counter()
    time.sleep(0.1)
    delta = time.perf_counter() - start
    return delta > 0.15  # 正常情况下应小于 0.11

# 检查 NtGlobalFlag 标志位
def check_nt_global_flag():
    PROCESS_BASIC_INFORMATION = ctypes.c_ulong * 6
    pbi = PROCESS_BASIC_INFORMATION()
    h_process = ctypes.windll.kernel32.GetCurrentProcess()
    ntdll = ctypes.windll.ntdll
    ret_len = ctypes.c_ulong()
    status = ntdll.NtQueryInformationProcess(
        h_process, 0, ctypes.byref(pbi), ctypes.sizeof(pbi), ctypes.byref(ret_len)
    )
    if status != 0:
        return False
    peb_base = pbi[1]
    nt_global_flag = ctypes.c_ulong()
    ctypes.windll.kernel32.ReadProcessMemory(
        h_process,
        peb_base + 0x68,  # NtGlobalFlag offset
        ctypes.byref(nt_global_flag),
        4,
        ctypes.byref(ret_len)
    )
    return nt_global_flag.value & 0x70 != 0  # 正常为 0，调试状态下为 0x70



# -----------------------------
# 反沙箱
# -----------------------------

def anti_sandbox_checks():
    start_time = time.time()

    if is_virtual_machine():
        print("[!] 检测到虚拟机环境，退出")
        sys.exit(1)

    if is_low_memory():
        print("[!] 内存过低，可能为沙箱，退出")
        sys.exit(1)

    if is_sandbox_user():
        print("[!] 用户名或主机名异常，退出")
        sys.exit(1)

    if has_suspicious_processes():
        print("[!] 检测到可疑进程，退出")
        sys.exit(1)

    time.sleep(1)  # 避免太快执行
    if time.time() - start_time < 1:
        print("[!] 启动过快，可能为沙箱环境，退出")
        sys.exit(1)

# -----------------------------
# 反调试
# -----------------------------

def anti_debug_all():
    print("[*] 正在执行反调试检测...")

    if is_debugger_present_combined():
        print("[!] 检测到调试器 (IsDebuggerPresent / RemoteDebugger)，退出")
        sys.exit(1)

    if is_being_debugged_peb():
        print("[!] PEB 被修改 (BeingDebugged 标志为真)，退出")
        sys.exit(1)

    # if detect_debug_break():
    #     print("[!] DebugBreak 未导致崩溃，可能被调试器接管，退出")
    #     sys.exit(1)

    if is_launched_by_debugger():
        print("[!] 父进程链中存在调试器痕迹，退出")
        sys.exit(1)

    if check_time_drift_strict():
        print("[!] 时间漂移异常，可能 Sleep 被 Hook，退出")
        sys.exit(1)

    if check_nt_global_flag():
        print("[!] NtGlobalFlag 标志位异常，可能处于调试状态，退出")
        sys.exit(1)

    print("[+] 未发现调试迹象，程序将继续运行。")


# -----------------------------
# 主程序开始
# -----------------------------
anti_sandbox_checks()
anti_debug_all()

a="print('Hello World!')"
exec(a)
